# active_window_client.py
import re
import time
import requests
import ctypes
from ctypes import wintypes
import sys
import hmac
import hashlib
import socket
import platform
import psutil
import GPUtil
import wmi

AUTH_CONFIG = {
    "appid": "",
    "token": ""
}

#SERVER_URL = f"http://localhost:5502/report"
#STATUS_URL = f"http://localhost:5502/status"
SERVER_URL = f""
STATUS_URL = f""

# 定义 Windows API 函数
user32 = ctypes.WinDLL('user32', use_last_error=True)
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

# 函数声明
GetForegroundWindow = user32.GetForegroundWindow
GetForegroundWindow.restype = wintypes.HWND

GetWindowTextLength = user32.GetWindowTextLengthW
GetWindowTextLength.argtypes = (wintypes.HWND,)
GetWindowTextLength.restype = ctypes.c_int

GetWindowText = user32.GetWindowTextW
GetWindowText.argtypes = (wintypes.HWND, wintypes.LPWSTR, ctypes.c_int)
GetWindowText.restype = ctypes.c_int

GetWindowThreadProcessId = user32.GetWindowThreadProcessId
GetWindowThreadProcessId.argtypes = (wintypes.HWND, ctypes.POINTER(wintypes.DWORD))
GetWindowThreadProcessId.restype = wintypes.DWORD

OpenProcess = kernel32.OpenProcess
OpenProcess.argtypes = (wintypes.DWORD, wintypes.BOOL, wintypes.DWORD)
OpenProcess.restype = wintypes.HANDLE

CloseHandle = kernel32.CloseHandle
CloseHandle.argtypes = (wintypes.HANDLE,)
CloseHandle.restype = wintypes.BOOL

QueryFullProcessImageName = kernel32.QueryFullProcessImageNameW
QueryFullProcessImageName.argtypes = (wintypes.HANDLE, wintypes.DWORD, wintypes.LPWSTR, ctypes.POINTER(wintypes.DWORD))
QueryFullProcessImageName.restype = wintypes.BOOL

# 常量
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000

# 生成访问令牌
def generate_access_token(timestamp):
    sign_str = f"{timestamp}:{AUTH_CONFIG['appid']}:{AUTH_CONFIG['token']}"
    return hmac.new(
        AUTH_CONFIG['token'].encode('utf-8'),
        sign_str.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()

# 使用 "stdin" 作为用户ID
USER_ID = "master"
PORT = 5502




CPU_MODEL_MAP = {
    "Intel(R) Core(TM) i9-14900KF": "Core i9-14900KF",
    "Intel(R) Core(TM) i7-13700K": "Core i7-13700K",
    "AMD Ryzen 9 7950X": "Ryzen 9 7950X",
    # 添加更多映射关系...
}

def get_friendly_cpu_name(raw_name):
    """将原始CPU名称转换为更友好的显示名称"""
    # 首先检查映射表中是否有匹配项
    for key, friendly_name in CPU_MODEL_MAP.items():
        if key in raw_name:
            return friendly_name

    # 尝试提取Intel Core i系列名称
    if "Intel(R) Core(TM)" in raw_name:
        match = re.search(r"i\d-\d+[A-Z]*", raw_name)
        if match:
            return f"Core {match.group(0)}"

    # 尝试提取AMD Ryzen系列名称
    if "AMD Ryzen" in raw_name:
        match = re.search(r"Ryzen [0-9 ]+[A-Z]*", raw_name)
        if match:
            return match.group(0)

    # 如果都无法识别，返回原始名称
    return raw_name

def get_device_info():
    try:
        # 获取基础信息
        device_name = socket.gethostname()
        os_info = f"{platform.system()} {platform.release()} ({platform.version()})"

        # 获取CPU信息
        #cpu_info = {
            #"name": platform.processor(),
            #"cores": psutil.cpu_count(logical=False),  # 物理核心
            #"logical_cores": psutil.cpu_count(logical=True),  # 逻辑核心
            #"usage": psutil.cpu_percent(interval=0.1)  # CPU使用率
        #}
        # 获取更友好的CPU信息
        cpu_info = {}
        try:
            # 使用WMI获取更详细的CPU信息（仅Windows）
            if platform.system() == 'Windows':
                import wmi
                c = wmi.WMI()
                for processor in c.Win32_Processor():
                    cpu_info["name"] = processor.Name
                    cpu_info["cores"] = processor.NumberOfCores
                    cpu_info["logical_cores"] = processor.NumberOfLogicalProcessors
                    cpu_info["usage"] = psutil.cpu_percent(interval=0.1)
                    break  # 只取第一个处理器
            else:
                # Linux/Mac系统使用其他方法
                cpu_info["name"] = get_friendly_cpu_name(platform.processor())
                cpu_info["cores"] = psutil.cpu_count(logical=False)
                cpu_info["logical_cores"] = psutil.cpu_count(logical=True)
                cpu_info["usage"] = psutil.cpu_percent(interval=0.1)
        except:
            # 回退到简单方法
            cpu_info["name"] = get_friendly_cpu_name(platform.processor())
            cpu_info["cores"] = psutil.cpu_count(logical=False)
            cpu_info["logical_cores"] = psutil.cpu_count(logical=True)
            cpu_info["usage"] = psutil.cpu_percent(interval=0.1)

        # 获取内存信息
        mem = psutil.virtual_memory()
        mem_info = {
            "total": round(mem.total / (1024 ** 3), 2),  # GB
            "used": round(mem.used / (1024 ** 3), 2),
            "available": round(mem.available / (1024 ** 3), 2),
            "percent": mem.percent
        }

        # 获取GPU信息
        gpu_info = {}
        try:
            gpus = GPUtil.getGPUs()
            if gpus:
                gpu = gpus[0]  # 取第一个GPU
                gpu_info = {
                    "name": gpu.name,
                    "driver": gpu.driver,
                    "vram_total": round(gpu.memoryTotal / 1024, 2),  # GB
                    "vram_used": round(gpu.memoryUsed / 1024, 2),
                    "vram_percent": gpu.memoryUtil * 100,  # 百分比
                    "gpu_usage": gpu.load * 100  # GPU使用率
                }
        except:
            # GPU信息获取失败时处理
            pass

        return {
            "device_name": device_name,
            "os": os_info,
            "cpu": cpu_info,
            "memory": mem_info,
            "gpu": gpu_info
        }
    except Exception as e:
        print(f"获取设备信息错误: {e}")
        return {
            "device_name": "未知设备",
            "os": "未知系统",
            "cpu": {},
            "memory": {},
            "gpu": {}
        }

def get_active_window():
    try:
        # 获取前台窗口句柄
        hwnd = GetForegroundWindow()

        # 获取窗口标题
        length = GetWindowTextLength(hwnd)
        if length > 0:
            buff = ctypes.create_unicode_buffer(length + 1)
            GetWindowText(hwnd, buff, length + 1)
            window_title = buff.value
        else:
            window_title = "无标题"

        # 获取进程ID
        pid = wintypes.DWORD()
        GetWindowThreadProcessId(hwnd, ctypes.byref(pid))

        # 获取进程名
        app_name = "未知应用"
        h_process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid.value)
        if h_process:
            try:
                buff_size = wintypes.DWORD(1024)
                buff = ctypes.create_unicode_buffer(buff_size.value)
                if QueryFullProcessImageName(h_process, 0, buff, ctypes.byref(buff_size)):
                    app_path = buff.value
                    app_name = app_path.split('\\')[-1]
            finally:
                CloseHandle(h_process)

        return app_name, window_title
    except Exception as e:
        print(f"获取窗口信息错误: {e}")
        return "未知应用", "未知标题"

def report_active_window():
    try:
        app_name, window_title = get_active_window()
        timestamp = int(time.time() * 1000)  # 当前毫秒时间戳
        device_info = get_device_info()  # 获取完整设备信息

        data = {
            "userId": USER_ID,
            "appName": app_name,
            "windowTitle": window_title,
            "timestamp": timestamp,  # 添加时间戳
            "appid": AUTH_CONFIG["appid"],  # 添加appid
            "access_token": generate_access_token(timestamp),  # 添加访问令牌
            "device_info": device_info  # 添加自动获取的设备名称
        }

        print(f"发送窗口信息: {device_info} - {app_name} - {window_title}")
        response = requests.post(SERVER_URL, json=data)
        return response.status_code == 200
    except Exception as e:
        print(f"发送窗口信息错误: {e}")
        return False

def send_status(status):
    try:
        timestamp = int(time.time() * 1000)  # 当前毫秒时间戳
        device_info = get_device_info()  # 获取完整设备信息

        data = {
            "userId": USER_ID,
            "status": status,
            "timestamp": timestamp,  # 添加时间戳
            "appid": AUTH_CONFIG["appid"],  # 添加appid
            "access_token": generate_access_token(timestamp),  # 添加访问令牌
            "deviceName": device_info  # 添加自动获取的设备名称
        }

        print(f"发送状态: {status}")
        response = requests.post(STATUS_URL, json=data)
        return response.status_code == 200
    except Exception as e:
        print(f"发送状态错误: {e}")
        return False


if __name__ == "__main__":
    print("Windows 活动窗口检测客户端已启动")
    print(f"用户ID: {USER_ID}")
    print(f"应用ID: {AUTH_CONFIG['appid']}")
    print(f"服务器地址: {SERVER_URL}")

    # 发送连接状态
    send_status("connected")

    try:
        last_status_time = time.time()
        while True:
            current_time = time.time()

            # 每30秒发送一次状态更新
            if current_time - last_status_time > 30:
                send_status("connected")
                last_status_time = current_time

            # 发送窗口报告
            success = report_active_window()
            if success:
                app_name, window_title = get_active_window()
                print(f"窗口信息已发送: {app_name} - {window_title}")
            else:
                print("发送窗口信息失败")

            time.sleep(5)  # 每5秒发送一次
    except KeyboardInterrupt:
        print("\n正在停止客户端...")
        send_status("disconnected")
        print("客户端已停止")